package de.g18.gruppe3.ldapinterface.service.provider;

import java.util.HashMap;

import de.g18.gruppe3.common.ldap.LDAPSynchronizationService;
import de.g18.gruppe3.common.ldap.LoginService;
import de.g18.gruppe3.common.ldap.OrganizationalUnitService;
import de.g18.gruppe3.common.ldap.UserGroupService;
import de.g18.gruppe3.common.ldap.UserService;

/**
 * Stellt Methoden zu verfügung um auf die einzelnen Services des LDAPClients zuzugreifen.
 * Die Klasse nutzt das Singelton-Pattern.
 *
 * @author <a href="mailto:kevinhuber.kh@gmail.com">Kevin Huber</a>
 */
public class LDAPServiceProvider {

    private static final String SERVICE_IMPLEMENTATION_PACKAGE = "de.g18.gruppe3.ldapinterface.service.";

    private static LDAPServiceProvider instance;

    private final HashMap<Class<?>, Object> services;


    private LDAPServiceProvider() {
        services = new HashMap<Class<?>, Object>();
    }

    public static LDAPServiceProvider getInstance() {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }

    private static synchronized LDAPServiceProvider createInstance() {
        return new LDAPServiceProvider();
    }

    public LoginService getLoginService() {
        return getService(LoginService.class);
    }

    public UserService getUserService() {
        return getService(UserService.class);
    }

    public UserGroupService getUserGroupService() {
        return getService(UserGroupService.class);
    }

    public OrganizationalUnitService getOrganizationalUnitService() {
        return getService(OrganizationalUnitService.class);
    }
    
    public LDAPSynchronizationService getLDAPSynchronizationService() {
        return getService(LDAPSynchronizationService.class);
    }

    @SuppressWarnings("unchecked")
    private <_Service extends Object> _Service getService(Class<_Service> aServiceClass) {
        _Service service = (_Service) services.get(aServiceClass);
        if (service == null) {
            service = createService(aServiceClass);
            services.put(aServiceClass, service);
        }
        return service;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private <_Service extends Object> _Service createService(Class<_Service> aServiceClass) {
        String className = SERVICE_IMPLEMENTATION_PACKAGE + aServiceClass.getSimpleName() + "Impl";
        Class serviceImplementation = null;
        try {
            serviceImplementation = Class.forName(className);
            return (_Service) serviceImplementation.newInstance();
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Can not find class '" + className + "'", e);
        } catch (InstantiationException e) {
            throw new IllegalStateException("Can not create new instance of class '" + className + "'", e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Can not access class '" + className + "'", e);
        }
    }
}
